package com.xsystem.criteria;

import java.util.ArrayList;
import java.util.List;

import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.ProjectionList;
import org.hibernate.criterion.Projections;

import com.xsystem.criteria.XsystemProjection.ProjectionType;

@SuppressWarnings("rawtypes")
public class XsystemCriteria {

	private List<XsystemProjection> projections = new ArrayList<XsystemProjection>();
	
	private List<XsystemExpression> expressions = new ArrayList<XsystemExpression>();
	
	private List<XsystemOrder> orders = new ArrayList<XsystemOrder>();
	
	private Class clazz;
	
	private XsystemCriteria(Class clazz) {
		this.clazz = clazz;
	}
	
	public static XsystemCriteria forClass(Class clazz) {
		return new XsystemCriteria(clazz);
	}
	
	public XsystemCriteria project(XsystemProjection projection) {
		projections.add(projection);
		return this;
	}
	
	public XsystemCriteria project(List<XsystemProjection> projectionList) {
		projections.addAll(projectionList);
		return this;
	}
	
	public XsystemCriteria with(XsystemExpression expression) {
		expressions.add(expression);
		return this;
	}
	
	public XsystemCriteria with(List<XsystemExpression> expressionList) {
		expressions.addAll(expressionList);
		return this;
	}
	
	public XsystemCriteria order(XsystemOrder order) {
		orders.add(order);
		return this;
	}
	
	public XsystemCriteria order(List<XsystemOrder> orderList) {
		orders.addAll(orderList);
		return this;
	}
	
	public DetachedCriteria toHibernateDetachedCriteria() {
		DetachedCriteria detachedCriteria = DetachedCriteria.forClass(clazz);
		for (XsystemExpression expression : expressions) {
			detachedCriteria.add(expression.toHibernateCriterion());
		}
		ProjectionList projectionList = Projections.projectionList();
		boolean distinct = false;
		for (XsystemProjection projection : projections) {
			if (projection.getProjectionType() == ProjectionType.DISTINCT) {
				distinct = true;
				continue;
			}
			projectionList.add(projection.toHibernateProjection());
		}
		if (projectionList.getLength() > 0) {
			detachedCriteria.setProjection(distinct ? Projections.distinct(projectionList) : projectionList);
		}
		for (XsystemOrder order : orders) {
			detachedCriteria.addOrder(order.toHibernateOrder());
		}
		return detachedCriteria;
	}
}
